"""
用户信息DAO层
负责用户表的数据库操作（增删改查）
"""
from typing import Optional, List, Dict, Any
from datetime import date, datetime
from app.db import db  # 与模型一致的db实例
from app.Models.AdminModels.UserModels.UserModel import User  # 导入User模型
from werkzeug.security import generate_password_hash  # 密码加密（与模型中密码哈希存储对应）


class UserDAO:
    """用户信息数据访问对象"""

    @staticmethod
    def add_user(
            username: str,
            email: str,
            password: str,
            birthday: Optional[date] = None,
            reg_time: Optional[datetime] = None
    ) -> Optional[User]:
        """
        添加新用户（注册功能核心）
        :param username: 用户名（3-20位，唯一）
        :param email: 绑定邮箱（唯一）
        :param password: 原始密码（将自动加密存储）
        :param birthday: 生日（可选）
        :param reg_time: 注册时间（可选，默认当前时间）
        :return: 新增的用户模型实例（失败返回None）
        """
        try:
            # 1. 检查用户名和邮箱是否已存在
            if User.query.filter_by(username=username).first():
                raise ValueError(f"用户名'{username}'已被注册")
            if User.query.filter_by(email=email).first():
                raise ValueError(f"邮箱'{email}'已被绑定")

            # 2. 密码加密（与模型中password字段的哈希存储对应）
            hashed_password = generate_password_hash(
                password,
                method='pbkdf2:sha256',  # 安全的加密算法
                salt_length=8
            )

            # 3. 构建用户实例
            new_user = User(
                username=username,
                email=email,
                password=hashed_password,
                birthday=birthday,
                reg_time=reg_time or datetime.now()
            )

            # 4. 提交到数据库
            db.session.add(new_user)
            db.session.commit()
            return new_user

        except ValueError as e:
            # 业务异常（用户名/邮箱重复）
            db.session.rollback()
            print(f"添加用户失败：{str(e)}")
            return None
        except Exception as e:
            # 数据库异常
            db.session.rollback()
            print(f"数据库错误：添加用户失败 - {str(e)}")
            return None

    @staticmethod
    def get_user_by_id(user_id: int) -> Optional[User]:
        """
        根据用户ID查询用户
        :param user_id: 用户主键ID
        :return: 用户模型实例（不存在返回None）
        """
        try:
            return User.query.filter_by(id=user_id).first()
        except Exception as e:
            print(f"查询用户失败（ID：{user_id}）：{str(e)}")
            return None

    @staticmethod
    def get_user_by_username(username: str) -> Optional[User]:
        """
        根据用户名查询用户（登录功能核心）
        :param username: 用户名
        :return: 用户模型实例（不存在返回None）
        """
        try:
            return User.query.filter_by(username=username).first()
        except Exception as e:
            print(f"查询用户失败（用户名：{username}）：{str(e)}")
            return None

    @staticmethod
    def get_user_by_email(email: str) -> Optional[User]:
        """
        根据邮箱查询用户（忘记密码/邮箱验证核心）
        :param email: 绑定邮箱
        :return: 用户模型实例（不存在返回None）
        """
        try:
            return User.query.filter_by(email=email).first()
        except Exception as e:
            print(f"查询用户失败（邮箱：{email}）：{str(e)}")
            return None

    @staticmethod
    def get_all_users(page: int = 1, per_page: int = 20) -> Dict[str, Any]:
        """
        分页查询所有用户（管理员后台核心）
        :param page: 页码（默认第1页）
        :param per_page: 每页条数（默认20条）
        :return: 包含用户列表和分页信息的字典
        """
        try:
            pagination = User.query.paginate(
                page=page,
                per_page=per_page,
                error_out=False  # 页码超出范围时返回空列表，不抛异常
            )
            return {
                "total": pagination.total,  # 总条数
                "pages": pagination.pages,  # 总页数
                "current_page": pagination.page,  # 当前页码
                "per_page": pagination.per_page,  # 每页条数
                "users": [user.to_dict() for user in pagination.items]  # 用户列表（字典格式）
            }
        except Exception as e:
            print(f"分页查询用户失败：{str(e)}")
            return {
                "total": 0,
                "pages": 0,
                "current_page": page,
                "per_page": per_page,
                "users": []
            }

    @staticmethod
    def update_user(
            user_id: int,
            **kwargs
    ) -> Optional[User]:
        """
        更新用户信息（支持部分字段更新）
        :param user_id: 要更新的用户ID
        :param kwargs: 要更新的字段（支持username/email/password/birthday）
        :return: 更新后的用户模型实例（失败返回None）
        """
        try:
            # 1. 查询用户是否存在
            user = UserDAO.get_user_by_id(user_id)
            if not user:
                raise ValueError(f"用户不存在（ID：{user_id}）")

            # 2. 处理特殊字段
            update_data = {}
            for key, value in kwargs.items():
                if key not in ['username', 'email', 'password', 'birthday']:
                    continue  # 忽略不支持的字段

                # 用户名唯一校验
                if key == 'username' and value != user.username:
                    if User.query.filter_by(username=value).first():
                        raise ValueError(f"用户名'{value}'已被占用")
                    update_data[key] = value

                # 邮箱唯一校验
                elif key == 'email' and value != user.email:
                    if User.query.filter_by(email=value).first():
                        raise ValueError(f"邮箱'{value}'已被绑定")
                    update_data[key] = value

                # 密码更新（需重新加密）
                elif key == 'password' and value:
                    update_data[key] = generate_password_hash(
                        value,
                        method='pbkdf2:sha256',
                        salt_length=16
                    )

                # 生日字段（直接赋值）
                elif key == 'birthday' and value:
                    update_data[key] = value

            # 3. 执行更新
            for key, value in update_data.items():
                setattr(user, key, value)

            db.session.commit()
            return user

        except ValueError as e:
            db.session.rollback()
            print(f"更新用户失败：{str(e)}")
            return None
        except Exception as e:
            db.session.rollback()
            print(f"数据库错误：更新用户失败 - {str(e)}")
            return None

    @staticmethod
    def delete_user(user_id: int) -> bool:
        """
        根据用户ID删除用户（管理员后台核心）
        :param user_id: 要删除的用户ID
        :return: 删除成功返回True，失败返回False
        """
        try:
            user = UserDAO.get_user_by_id(user_id)
            if not user:
                print(f"删除用户失败：用户不存在（ID：{user_id}）")
                return False

            db.session.delete(user)
            db.session.commit()
            return True
        except Exception as e:
            db.session.rollback()
            print(f"数据库错误：删除用户失败 - {str(e)}")
            return False

    @staticmethod
    def check_user_exist(username: Optional[str] = None, email: Optional[str] = None) -> bool:
        """
        检查用户名或邮箱是否已存在（注册表单验证核心）
        :param username: 要检查的用户名（可选）
        :param email: 要检查的邮箱（可选）
        :return: 存在返回True，不存在返回False
        """
        try:
            if username:
                return User.query.filter_by(username=username).first() is not None
            if email:
                return User.query.filter_by(email=email).first() is not None
            return False
        except Exception as e:
            print(f"检查用户存在性失败：{str(e)}")
            return False  # 异常时默认视为存在（避免重复注册）
